package cn.ac.cintcm.synonymous;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVStrategy;
import org.apache.log4j.Logger;

public class CSVDataSource extends DataSource{


    private static Logger logger = Logger.getLogger(CSVDataSource.class);

    private static CSVDataSource ds;
    
    public synchronized static CSVDataSource createDataSource(String fileName) 
                throws FileNotFoundException, IOException {
        if (ds == null || Config.reloaded) {
            ds = new CSVDataSource(fileName);
        }
        return ds;
    }
    
    protected CSVDataSource(String fileName) throws FileNotFoundException, IOException {
        data = readData(fileName);
        this.url = Config.getDataDir() + fileName;
        this.name = fileName;
        this.type = Config.FILE_CSV;
        this.idField = Config.getIDField();
        this.primaryField = Config.getPrimaryField();
        this.synonymousField = Config.getSynonymousField();
        this.displayFields = Config.getDisplayFields();
        fieldsMap = new HashMap<String, Integer>();
        for (int i = 0; i < data[0].length; i++) {
            fieldsMap.put(data[0][i], i);
        }
        idMap = new HashMap<String, Integer>();
        for (int i = 1; i < data.length; i++) {
            idMap.put(data[i][getFieldIndex(ID)], i);
        }
    }
    
    public static String[][] readData(String fileName) throws FileNotFoundException, IOException {
        File file = new File(Config.getDataDir() + fileName);
        BufferedReader reader = null;
        String[][] datas = null;
        try {
            reader = new BufferedReader(new FileReader(file));
            datas = (new CSVParser(reader,
                    CSVStrategy.DEFAULT_STRATEGY)).getAllValues();
            reader.close();
        } catch (FileNotFoundException e) {
            if (reader != null) {
                reader.close();
            }
            throw new FileNotFoundException();
        }
        return datas;
    }
    
    public synchronized Message writeData(String fileName) {
        File outfile = null;
        Message m = new Message();
        if (fileName != null) {
            this.url = Config.getDataDir() + fileName;
            outfile = new File(url + ".tmp");
        }
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(outfile));
            CSVPrinter p = new CSVPrinter(writer);
            p.println(data);       
            writer.close();
            m.setSuccess(true);
        } catch (IOException e) {
            m.setMsg(e.getMessage());
            e.printStackTrace();
        }
        if (m.isSuccess()) {
            File newFile = new File(url);
            boolean success = true;
            if (newFile.exists()) {
                success = newFile.delete();
            }
            success = outfile.renameTo(newFile) && success;
            m.setSuccess(success);
        }

        return m;
    }
    
    public static void writeData(String fileName, String[][] data) {
        File outfile = null;
        if (fileName != null) {
            String str = Config.getDataDir() + fileName;
            outfile = new File(str);
        }
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(outfile));
            CSVPrinter p = new CSVPrinter(writer);
            p.println(data);        
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static String[][] importData(String fileName) throws FileNotFoundException, IOException {
        String[][] data = readData(fileName);
        String[][] newData = null;
        if (data != null) {
            int newLength = data[0].length + EXPAND_FIELD_SIZE;
            newData = new String[data.length][newLength];
            newData[0][0] = ID;
            newData[0][1] = STATE;
            newData[0][2] = EDITOR;
            newData[0][3] = DATE;
            System.arraycopy(data[0], 0, newData[0], EXPAND_FIELD_SIZE, data[0].length);
            for (int i =1; i < data.length; i++) {
                newData[i] = new String[newLength];
                newData[i][0] = i + "";
                newData[i][1] = INIT_STATE; 
                newData[i][2] = "";
                newData[i][3] = ""; 
                System.arraycopy(data[i], 0, newData[i], EXPAND_FIELD_SIZE, data[i].length);
            }
        }
        return newData;
    }

    
    public void writeXML(String fileName) throws IOException {
        File outfile = new File(Config.getDataDir() + fileName);
        BufferedWriter writer = new BufferedWriter(new FileWriter(outfile));
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i < data.length; i++) {
            sb.append("<record id=\"");
            sb.append(data[i][0]);
            sb.append("\" lcyjmc=\"");
            sb.append(data[i][1]);
            sb.append("\" qkmc=\"");
            sb.append(data[i][2]);
            sb.append("\" />");
            sb.append(Config.ROW_SEPERATOR);
            writer.write(sb.toString());
            sb.setLength(0);
        }
    }

    @Override
    public Message write() {
        Message m = this.writeData(name);
        return m;
    }
    
    public static Message readMetaData(String fileName, List metaData) {
        Message msg = new Message();
        try {
            metaData.addAll(Arrays.asList(readData(fileName)[0]));
            msg.setSuccess(true);
        } catch (FileNotFoundException e) {
            msg.setMsg(e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            msg.setMsg(e.getMessage());
            e.printStackTrace();
        }
        return msg;
    }

}
